<template>
  <div>
    <el-card>
    <category-selector :disabled="!isShowList"></category-selector>
  </el-card>
  <el-card style="margin-top: 20px;">
    <div v-show="isShowList">
      <el-button type="primary" :icon="Plus" @click="showAdd" :disabled="!category3Id">添加属性</el-button>
      <el-table border :data="attrList">
        <el-table-column label="序号" type="index" align="center" width="80"></el-table-column>
        <el-table-column label="属性名称" width="150" prop="attrName"></el-table-column>
        <el-table-column label="属性值列表">
          <template v-slot="{row}">
            <el-tag v-for=" value in row.attrValueList" :key="value.id" style="margin-right: 5px;">{{ value.valueName }}</el-tag>
          </template>
        </el-table-column>
        <el-table-column label="操作" width="150">
          <template v-slot="{row}">
            <el-button type="primary" :icon="Edit" size="small" @click="showUpdate(row)"></el-button>
            <el-popconfirm :title="`确定删除${row.attrName}吗?`" @confirm="remove(row.id)">
              <template #reference>
                <el-button type="danger" :icon="Delete" size="small"></el-button>
              </template>
            </el-popconfirm>
            
          </template>
        </el-table-column>
      </el-table>
    </div>
    <div v-show="!isShowList">
      <span>属性名</span>
      <el-input v-model="attr.attrName" style="width: 200px; margin-left: 15px;"></el-input>

      <div style="margin: 20px 0;">
        <el-button type="primary" :icon="Plus" @click="addAttrValue">添加属性值</el-button>
        <el-button @click="isShowList=true">取消</el-button>
      </div>

      <el-table :data="attr.attrValueList">
        <el-table-column label="序号" type="index" width="80" align="center"></el-table-column>
        <el-table-column label="属性值名称">
          <template #default="{row, $index}">
            <!-- 通过判断标识isEdit来确定是显示span还是显示input -->
            <el-input ref="inputRef" v-if="row.isEdit" v-model="row.valueName" @blur="toShow(row, $index)"></el-input>
            <span v-else @click="toEdit(row)" style="display: inline-block;width: 100%;">{{ row.valueName }}</span>
          </template>
        </el-table-column>
        <el-table-column label="操作">
          <template #default="{$index}">
            <el-button type="danger" size="small" :icon="Delete" @click="attr.attrValueList.splice($index, 1)"></el-button>
          </template>
        </el-table-column>
      </el-table>

      <div style="margin: 20px 0;">
        <el-button type="primary" @click="save" :disabled="isSaveDisabled">保存</el-button>
        <el-button @click="isShowList=true">取消</el-button>
      </div>
    </div>
  </el-card>
  </div>
</template>

<script lang="ts">
export default {
  name: 'Attr',
}
</script>

<script lang="ts" setup>
import type { AttrListModel, AttrModel, AttrValueModel } from '@/api/product/model/AttrModel';
import { Delete, Edit, Plus } from '@element-plus/icons-vue';
import {ref, watch, reactive, nextTick, computed} from 'vue'
import {useCategoryStore} from '@/stores/category'
import { storeToRefs } from 'pinia';
import { deleteAttrApi, getAttrListApi, saveAttrApi } from '@/api/product/attr';

import {ElInput, ElMessage} from 'element-plus'
import { cloneDeep } from 'lodash';

// 测试InstanceType的使用
// import Trademark from '../trademark/index.vue'
// const trademarkRef = ref<InstanceType<typeof Trademark>>()
// trademarkRef.value?.getList2()

// 用来判断是否禁用保存按钮的计算属性
const isSaveDisabled = computed(() => {
  // 只有指定属性名及至少有一个属性值(必须有属性值名称)
  const hasName = !!attr.attrName  
  // 判断属性值列表中是否至少有一个有属性值名称
  const hasAttrValue = attr.attrValueList.some(value => value.valueName)

  // 如果没有属性名或者没有属性值都是禁用的, 返回true
  return !hasName || !hasAttrValue
})


// 删除指定的属性
const remove = async (id: number) => {
  // 请求删除接口
  await deleteAttrApi(id)
  // 成功之后: 提示 / 重新获取列表
  ElMessage.success('删除成功!')
  getList()
}


/* 添加/更新属性 start */

// 请求保存属性
const save = async () => {
  // 发请求前整理/处理要提交的数据: attr
  //   删除属性值对象中的isEdit
  attr.attrValueList.forEach(value => delete value.isEdit)
  //   指定categoryId的值为category3Id.value
  attr.categoryId = category3Id.value as number
  // 发送添加/更新属性的请求
  await saveAttrApi(attr)
  // 成功后, 提示 / 回到列表页面/重新获取列表
  ElMessage.success('保存属性成功!')
  isShowList.value = true
  getList()
}

const addAttrValue = () => {
  // 创建一个新的属性值对象
  const attrValue: AttrValueModel = {
    valueName: '', // 属性值名称
    attrId: attr.id, // 属性的id
    isEdit: true, // 标识显示input
  }
  // 添加到属性值列表中attr.attrValueList
  attr.attrValueList.push(attrValue)

  // 自动获取焦点: nextTick + input.focus()
  nextTick(()=> inputRef.value?.focus())
}

// typeof: 得到类型
// InstanceType: 得到实例的类型   ==> 指定ref中的value保存el-input组件对象
const inputRef = ref<InstanceType<typeof ElInput>>()
// 变为编辑模式
const toEdit = (row: AttrValueModel) => {
  // 将isEdit变为true
  row.isEdit = true

  // 通过ref得到ElInput, 并调用其focus方法获得焦点
  // 不行: 更新数据后, dom是异步更新的, 直接同步获取不到更新后dom
  // inputRef.value?.focus()
  // 解决: 等到dom更新后再去获取 => 使用nextTick
  nextTick(() => {
    inputRef.value?.focus()
  })

}

// 变为查看模式
const toShow = (row: AttrValueModel, index: number) => {
  // 如果没有名称, 失去焦点时存在一个空行  ==> 删除这个属性值对象
  if (!row.valueName) {
    attr.attrValueList.splice(index, 1)
    return
  }
  // 如果与其它重名了, 失去焦点存在同名的2行 ==>  删除这个属性值对象
  // attr.attrValueList [{}, {valueName: 'a'}, {valueName: 'a'}]
  // 方式一: 如果有2个属性值对象的valueName等于row.valueName, 就重名了
  // const isRepeat = attr.attrValueList.filter(value => value.valueName===row.valueName).length===2
  // 方式二: 如果除了自己外, 还有一个的valueName等于row.valueName, 就重名了
  const isRepeat = attr.attrValueList.some(item => item!=row && item.valueName===row.valueName)
  if (isRepeat) {
    attr.attrValueList.splice(index, 1)
    return
  }

  // 将isEdit变为false
  row.isEdit = false
}




const isShowList = ref(true)  // 是否显示列表
const initAttr = () => ({
  attrName: '',
  attrValueList: [],
  categoryId: 0,
  categoryLevel: 3
})
// const attr = reactive<AttrModel>({
//   attrName: '',
//   attrValueList: [],
//   categoryId: 0,
//   categoryLevel: 3
// })
const attr = reactive<AttrModel>(initAttr())

// 显示添加界面
const showAdd = () => {
  // 重置attr
  // Object.assign(obj1, ...objs) // 将后面任意多个对象中的属性添加到obj1中
  // Object.assign(attr, {
  //   attrName: '',
  //   attrValueList: [],
  //   categoryId: 0,
  //   categoryLevel: 3
  // })
  Object.assign(attr, initAttr())
  // 显示
  isShowList.value = false
}

// 显示更新属性界面
const showUpdate = (row: AttrModel) => {
  // 将当前指定的属性对象保存中attr中
  // 共享同一个attrValueList, 里面的attrValue也是同一个 => 修改时就直接修改
  // Object.assign(attr, row)   
  // 解决办法: 使用lodash对row进行深拷贝
  Object.assign(attr, cloneDeep(row)) 
  // 显示
  isShowList.value = false
}

/* 添加/更新属性 end*/


/* 属性列表 start */
// 属性列表
const attrList = ref<AttrListModel>([])
// 取出pinia管理的三级分类id
const {category1Id, category2Id, category3Id} = storeToRefs(useCategoryStore())
// 监视category3Id
watch(category3Id, (val) => {
  // 有值时才去请求, 没值清除已有属性列表
  if (val) {
    getList()
  } else {
    // 清空attrList
    attrList.value = []
  }
})

// 请求获取属性列表显示
async function getList() {
  // 请求获取属性列表, 并保存到attrList
  attrList.value = await getAttrListApi({
      category1Id: category1Id.value as number, 
      category2Id: category2Id.value as number, 
      category3Id: category3Id.value as number
    })
}
/* 属性列表 end */  


</script>

<style lang="scss" scoped>

</style>

